<!DOCTYPE html>
            
<HTML>
<HEAD>
<meta name="booktitle" content="Developing Applications With Objective Caml" >
 <meta charset="ISO-8859-1"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<META name="GENERATOR" content="hevea 1.05-7 of 2000-02-24">
<META NAME="Author" CONTENT="Christian.Queinnec@lip6.fr">
<LINK rel=stylesheet type="text/css" href="videoc-ocda.css">
<script language="JavaScript" src="videoc.js"><!--
//--></script>
<TITLE>
 Types and Genericity
</TITLE>
</HEAD>
<BODY class="regularBody">
<A HREF="book-ora142.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora144.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
<HR>

<H2> Types and Genericity</H2>
Besides the ability to model a problem using aggregation and inheritance
relations, object-oriented programming is interesting because it provides the ability
to reuse or modify the behavior of classes. However, extending an Objective CAML
class must preserve the static typing properties of the language.<BR>
<BR>
<A NAME="@concepts314"></A>
<A NAME="@concepts315"></A>
With abstract classes, you can factorize code and group their
subclasses into one
``communication protocol''. An abstract class fixes the
names and types of messages that may be received by instances of
child classes. This technique will be better appreciated in
connection with multiple inheritance.<BR>
<BR>
The notion of an open object type (or simply an open type) that
specifies the required methods allows code to work with instances using generic
functions. But you may need to make the type constraints precise; this will be
necessary for parameterized classes, which provide the genericity of
parameterized polymorphism in the context of classes. With this latter
object layer feature, Objective CAML can really be generic.<BR>
<BR>
<A NAME="toc207"></A>
<H3> Abstract Classes and Methods</H3><A NAME="@concepts316"></A>
<A NAME="@concepts317"></A>
<A NAME="@concepts318"></A>
<A NAME="@concepts319"></A>
<A NAME="@concepts320"></A>
<A NAME="@concepts321"></A>
<A NAME="@concepts322"></A>
<A NAME="@concepts323"></A>
<A NAME="@fonctions392"></A>
In abstract classes, some methods are declared without a body. Such
methods are called abstract. It is illegal to instantiate an abstract
class; <B>new</B> cannot be used. The keyword <B>virtual</B> is used to
indicate that a class or method is abstract.


<H3> Syntax </H3> <HR>


<B>class</B> <B>virtual</B> <I>name</I> <B>=</B> 
<B>object</B> ...<B>end</B>



<HR>


A class <EM>must</EM> be declared abstract as soon as one of its methods is
abstract. A method is declared abstract by providing only the method type.


<H3> Syntax </H3> <HR>


<B>method</B> <B>virtual</B> <I>name</I> : <I>type</I>



<HR>

<BR>
<BR>
When a subclass of an abstract class redefines <EM>all</EM> of the abstract
methods of its parent, then it may become concrete; otherwise it also has to
be declared abstract.<BR>
<BR>
As an example, suppose we want to construct a set of displayable objects, all with a method
<TT>print</TT> that will display the object's contents translated into a
character string. All such objects need a method
<TT>to_string</TT>. We define class <TT>printable</TT>.
The string may vary according to the nature of the objects that we consider;
therefore method <TT>to_string</TT> is abstract in the declaration of
<TT>printable</TT> and consequently the class is also abstract.
<A NAME="ex-printable"></A>


<PRE><BR># <B>class</B><CODE> </CODE><B>virtual</B><CODE> </CODE>printable<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><TT>(</TT>self<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE><B>virtual</B><CODE> </CODE>to_string<CODE> </CODE><CODE>:</CODE><CODE> </CODE>unit<CODE> </CODE>-&gt;<CODE> </CODE>string<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>print<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>print_string<CODE> </CODE><TT>(</TT>self#to_string()<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR><CODE>class virtual printable :</CODE><BR><CODE>  unit -&gt;</CODE><BR><CODE>  object</CODE><BR><CODE>    method print : unit -&gt; unit</CODE><BR><CODE>    method virtual to_string : unit -&gt; string</CODE><BR><CODE>  end</CODE><BR>

</PRE>

We note that the abstractness of the class and of its method
<TT>to_string</TT> is made clear in the type we obtain.<BR>
<BR>
From this class, let us try to define the class hierarchy of figure <A HREF="book-ora143.html#fig-relations">15.4</A>.<BR>
<BR>
<BLOCKQUOTE><DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV>
<DIV ALIGN=center>
<IMG SRC="book-ora061.gif">
</DIV>
<BR>
<DIV ALIGN=center>Figure 15.4: Relations between classes of displayable objects.</DIV><BR>

<A NAME="fig-relations"></A>
<DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV></BLOCKQUOTE>It is easy to redefine the classes <I>point</I>, <I>colored_point</I> and
<I>picture</I> by adding to their declarations a line <EM>inherit
printable ()</EM> that provides them with a method <I>print</I> through inheritance.


<PRE>


</PRE>



<PRE><BR># <B>let</B><CODE> </CODE>p<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>new</B><CODE> </CODE>point<CODE> </CODE><TT>(</TT><CODE>1</CODE><CODE>,</CODE><CODE>1</CODE><TT>)</TT><CODE> </CODE><B>in</B><CODE> </CODE>p#print()<CODE> </CODE>;;<BR><CODE>( 1, 1)- : unit = ()</CODE><BR># <B>let</B><CODE> </CODE>pc<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>new</B><CODE> </CODE>colored_point<CODE> </CODE><TT>(</TT><CODE>2</CODE><CODE>,</CODE><CODE>2</CODE><TT>)</TT><CODE> </CODE><CODE>"blue"</CODE><CODE> </CODE><B>in</B><CODE> </CODE>pc#print()<CODE> </CODE>;;<BR><CODE>( 2, 2) with color blue- : unit = ()</CODE><BR># <B>let</B><CODE> </CODE>t<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>new</B><CODE> </CODE>picture<CODE> </CODE><CODE>3</CODE><CODE> </CODE><B>in</B><CODE> </CODE>t#add<CODE> </CODE><TT>(</TT><B>new</B><CODE> </CODE>point<CODE> </CODE><TT>(</TT><CODE>1</CODE><CODE>,</CODE><CODE>1</CODE><TT>)</TT><TT>)</TT><CODE> </CODE>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>t#add<CODE> </CODE><TT>(</TT><B>new</B><CODE> </CODE>point<CODE> </CODE><TT>(</TT><CODE>3</CODE><CODE>,</CODE><CODE>2</CODE><TT>)</TT><TT>)</TT><CODE> </CODE>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>t#add<CODE> </CODE><TT>(</TT><B>new</B><CODE> </CODE>point<CODE> </CODE><TT>(</TT><CODE>1</CODE><CODE>,</CODE><CODE>4</CODE><TT>)</TT><TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>t#print()<CODE> </CODE>;;<BR><CODE>[ ( 1, 1) ( 3, 2) ( 1, 4)]- : unit = ()</CODE><BR>

</PRE>
<BR>
<BR>
Subclass <I>rectangle</I> below inherits from <I>printable</I>, and defines
method <TT>to_string</TT>. Instance variables <TT>llc</TT> (resp. <TT>urc</TT>) 
mean the lower left corner point (resp. upper right corner point) in the rectangle.


<PRE><BR># <B>class</B><CODE> </CODE>rectangle<CODE> </CODE><TT>(</TT>p1<CODE>,</CODE>p2<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE>printable<CODE> </CODE>()<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>llc<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT>p1<CODE> </CODE><CODE>:</CODE><CODE> </CODE>point<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>urc<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT>p2<CODE> </CODE><CODE>:</CODE><CODE> </CODE>point<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>to_string<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>"["</CODE><CODE> </CODE><CODE>^</CODE><CODE> </CODE>llc#to_string()<CODE> </CODE><CODE>^</CODE><CODE> </CODE><CODE>","</CODE><CODE> </CODE><CODE>^</CODE><CODE> </CODE>urc#to_string()<CODE> </CODE><CODE>^</CODE><CODE> </CODE><CODE>"]"</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR><CODE>class rectangle :</CODE><BR><CODE>  point * point -&gt;</CODE><BR><CODE>  object</CODE><BR><CODE>    val llc : point</CODE><BR><CODE>    val urc : point</CODE><BR><CODE>    method print : unit -&gt; unit</CODE><BR><CODE>    method to_string : unit -&gt; string</CODE><BR><CODE>  end</CODE><BR>

</PRE>
<BR>
<BR>
Class <I>rectangle</I> inherits from the abstract class <I>printable</I>,
and thus receives method <TT>print</TT>. It has two instance variables of type
<I>point</I>: the lower left corner (<TT>llc</TT>) and upper right corner.
Method <TT>to_string</TT> sends the message <TT>to_string</TT> to
its <TT>point</TT> instance variables <TT>llc</TT> and <TT>urc</TT>.<BR>
<BR>


<PRE><BR># <B>let</B><CODE> </CODE>r<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>new</B><CODE> </CODE>rectangle<CODE> </CODE><TT>(</TT><B>new</B><CODE> </CODE>point<CODE> </CODE><TT>(</TT><CODE>2</CODE><CODE>,</CODE><CODE>3</CODE><TT>)</TT><CODE>,</CODE><CODE> </CODE><B>new</B><CODE> </CODE>point<CODE> </CODE><TT>(</TT><CODE>4</CODE><CODE>,</CODE><CODE>5</CODE><TT>)</TT><TT>)</TT>;;<BR><CODE>val r : rectangle = &lt;obj&gt;</CODE><BR># r#print();;<BR><CODE>[( 2, 3),( 4, 5)]- : unit = ()</CODE><BR>

</PRE>
<BR>
<BR>
<A NAME="toc208"></A>
<H3> Classes, Types, and Objects</H3>
<A NAME="@concepts324"></A>
<A NAME="subsec-classes-types-objets"></A>
You may remember that the type of an object is determined by the type of its
methods. For instance, the type <I>point</I>, inferred during the declaration of
class <I>point</I>, is an abbreviation for type: 
<PRE>
  point =
    &lt; distance : unit -&gt; float; get_x : int; get_y : int;
      moveto : int * int -&gt; unit; rmoveto : int * int -&gt; unit;
      to_string : unit -&gt; string  &gt;
</PRE> 
This is a closed type; that is, all methods and associated types are fixed.
No additional methods and types are allowed. Upon a class declaration, the mechanism of type
inference computes the closed type associated with class. <BR>
<BR>

<H4> Open Types</H4>
<A NAME="@concepts325"></A>
<A NAME="@concepts326"></A>
Since sending a message to an object is part of the language, you may
define a function that sends a message to an object whose type is still undefined.


<PRE><BR># <B>let</B><CODE> </CODE>f<CODE> </CODE>x<CODE> </CODE><CODE>=</CODE><CODE> </CODE>x#get_x<CODE> </CODE>;;<BR><CODE>val f : &lt; get_x : 'a; .. &gt; -&gt; 'a = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
The type inferred for the argument of <TT>f</TT> is an object type, since a
message is sent to <TT>x</TT>, but this object type is open. In
function <TT>f</TT>, parameter <TT>x</TT> must have at least a method
<TT>get_x</TT>. Since the result of sending this message is not used within
function <TT>f</TT>, its type has to be as general as possible (i.e. a variable
of type <I>'a</I>). So type inference allows the function
<TT>f</TT> to be used with any object having a method <TT>get_x</TT>.
The double points (..) at the end of the type <I>&lt; get_x : 'a; .. &gt;</I>
indicate that the type of <TT>x</TT> is open.<BR>
<BR>


<PRE><BR># f<CODE> </CODE><TT>(</TT><B>new</B><CODE> </CODE>point<TT>(</TT><CODE>2</CODE><CODE>,</CODE><CODE>3</CODE><TT>)</TT><TT>)</TT><CODE> </CODE>;;<BR><CODE>- : int = 2</CODE><BR># f<CODE> </CODE><TT>(</TT><B>new</B><CODE> </CODE>colored_point<TT>(</TT><CODE>2</CODE><CODE>,</CODE><CODE>3</CODE><TT>)</TT><CODE> </CODE><CODE>"emerald"</CODE><TT>)</TT><CODE> </CODE>;;<BR><CODE>- : int = 2</CODE><BR># <B>class</B><CODE> </CODE>c<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>get_x<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>"I have a method get_x"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR><CODE>class c : unit -&gt; object method get_x : string end</CODE><BR># f<CODE> </CODE><TT>(</TT><B>new</B><CODE> </CODE>c<CODE> </CODE>()<TT>)</TT><CODE> </CODE>;;<BR><CODE>- : string = "I have a method get_x"</CODE><BR>

</PRE>
<BR>
<BR>
Type inference for classes may generate open types, particularly for initial
values in instance construction. The following example constructs a class
<I>couple</I>, whose initial values <TT>a</TT> and <TT>b</TT> have a method
<TT>to_string</TT>.


<PRE><BR># <B>class</B><CODE> </CODE>couple<CODE> </CODE><TT>(</TT>a<CODE>,</CODE>b<TT>)</TT><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>p0<CODE> </CODE><CODE>=</CODE><CODE> </CODE>a<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>p1<CODE> </CODE><CODE>=</CODE><CODE> </CODE>b<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>to_string()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>p0#to_string()<CODE> </CODE><CODE>^</CODE><CODE> </CODE>p1#to_string()<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>copy<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>new</B><CODE> </CODE>couple<CODE> </CODE><TT>(</TT>p0<CODE>,</CODE>p1<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR><CODE>class couple :</CODE><BR><CODE>  (&lt; to_string : unit -&gt; string; .. &gt; as 'a) *</CODE><BR><CODE>  (&lt; to_string : unit -&gt; string; .. &gt; as 'b) -&gt;</CODE><BR><CODE>  object</CODE><BR><CODE>    val p0 : 'a</CODE><BR><CODE>    val p1 : 'b</CODE><BR><CODE>    method copy : unit -&gt; couple</CODE><BR><CODE>    method to_string : unit -&gt; string</CODE><BR><CODE>  end</CODE><BR>

</PRE>

<A NAME="poo-as"></A> <A NAME="@fonctions393"></A>
The types of both <TT>a</TT> and <TT>b</TT> are open types, with method
<TT>to_string</TT>. We note that these two types are considered to be
different.
They are marked ``<I>as 'a</I>'' and ``<I>as 'b</I>'', respectively. Variables of 
types <I>'a</I> and <I>'b</I> are constrained by the generated type.<BR>
<BR>
<A NAME="@fonctions394"></A>
We use the sharp symbol to indicate the open type built from a closed type
<I>obj_type</I>:


<H3> Syntax </H3> <HR>

 <I>#obj_type</I> 


<HR>


The type obtained contains all of the methods of type <I>obj_type</I> and
terminates with a double point. <BR>
<BR>

<H4> Type Constraints.</H4><A NAME="sec-coercion-type"></A>
<A NAME="@concepts327"></A>
In the chapter on functional programming (see page <A HREF="book-ora015.html#subsec-poly">??</A>), we
showed how an expression can be constrained to have a type more precise
than what is produced by inference. Object types (open or closed) can be used to
enhance such constraints. One may want to open a priori the type of a
defined object, in order to apply it to a forthcoming method. We can use an
open object constraint:


<H3> Syntax </H3> <HR>

<B>(</B><I>name</I><B>:</B><I>#type</I><B>)</B>


<HR>


Which allows us to write:


<PRE><BR># <B>let</B><CODE> </CODE>g<CODE> </CODE><TT>(</TT>x<CODE> </CODE><CODE>:</CODE><CODE> </CODE>#point<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE>x#message;;<BR><CODE>val g :</CODE><BR><CODE>  &lt; distance : unit -&gt; float; get_x : int; get_y : int; message : 'a;</CODE><BR><CODE>    moveto : int * int -&gt; unit; print : unit -&gt; unit;</CODE><BR><CODE>    rmoveto : int * int -&gt; unit; to_string : unit -&gt; string; .. &gt; -&gt;</CODE><BR><CODE>  'a = &lt;fun&gt;</CODE><BR>

</PRE>

The type constraint with <I>#</I><I>point</I> forces <TT>x</TT> to have at
least all of the methods of <I>point</I>, and sending message
``<TT>message</TT>'' adds a method to the type of parameter <TT>x</TT>.<BR>
<BR>
Just as in the rest of the language, the object extension of Objective CAML provides
static typing through inference. When this mechanism does not have enough
information to determine the type of an expression, a type variable is
assigned. We have just seen that this process is also valid for typing objects;
however, it sometimes leads to ambiguous situations which the user must
resolve by explicitly giving type information.


<PRE><BR># <B>class</B><CODE> </CODE>a_point<CODE> </CODE>p0<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>p<CODE> </CODE><CODE>=</CODE><CODE> </CODE>p0<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>to_string()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>p#to_string()<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR><CODE>Characters 6-89:</CODE><BR><CODE>Some type variables are unbound in this type:</CODE><BR><CODE>  class a_point :</CODE><BR><CODE>    (&lt; to_string : unit -&gt; 'b; .. &gt; as 'a) -&gt;</CODE><BR><CODE>    object val p : 'a method to_string : unit -&gt; 'b end</CODE><BR><CODE>The method to_string has type unit -&gt; 'a where 'a is unbound</CODE><BR>

</PRE>
<BR>
<BR>
We resolve this ambiguity by saying that parameter <TT>p0</TT> has type <I>#point</I>.


<PRE><BR># <B>class</B><CODE> </CODE>a_point<CODE> </CODE><TT>(</TT>p0<CODE> </CODE><CODE>:</CODE><CODE> </CODE>#point<TT>)</TT><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>p<CODE> </CODE><CODE>=</CODE><CODE> </CODE>p0<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>to_string()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>p#to_string()<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR><CODE>class a_point :</CODE><BR><CODE>  (#point as 'a) -&gt; object val p : 'a method to_string : unit -&gt; string end</CODE><BR>

</PRE>

<A NAME="@concepts328"></A>
<A NAME="@fonctions395"></A><BR>
<BR>
In order to set type constraints in several places in a class declaration, the
following syntax is used:


<H3> Syntax </H3> <HR>


 <B>constraint</B> <I>type</I><SUB><I><FONT SIZE=2>1</FONT></I></SUB> = <I>type</I><SUB><I><FONT SIZE=2>2</FONT></I></SUB>



<HR>


The above example can be written specifying that parameter <TT>p0</TT> has type
<I>'a</I>, then putting a type constraint upon variable <I>'a</I>.


<PRE><BR># <B>class</B><CODE> </CODE>a_point<CODE> </CODE><TT>(</TT>p0<CODE> </CODE><CODE>:</CODE><CODE> </CODE><I>'a</I><TT>)</TT><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>constraint</B><CODE> </CODE><I>'a</I><CODE> </CODE><CODE>=</CODE><CODE> </CODE>#point<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>p<CODE> </CODE><CODE>=</CODE><CODE> </CODE>p0<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>to_string()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>p#to_string()<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR><CODE>class a_point :</CODE><BR><CODE>  (#point as 'a) -&gt; object val p : 'a method to_string : unit -&gt; string end</CODE><BR>

</PRE>
<BR>
<BR>
Several type constraints can be given in a class declaration.<BR>
<BR>


<H3> Warning </H3> <HR>


An open type cannot appear as the type of a method. 



<HR>

<BR>
<BR>
This strong restriction exists because an open type contains an
uninstantiated type variable coming from the rest of the type. Since one cannot
have a free variable type in a type declaration, a method containing such
a type is rejected by type inference.


<PRE><BR># <B>class</B><CODE> </CODE>b_point<CODE> </CODE>p0<CODE> </CODE><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE>a_point<CODE> </CODE>p0<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>get<CODE> </CODE><CODE>=</CODE><CODE> </CODE>p<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR><CODE>Characters 6-77:</CODE><BR><CODE>Some type variables are unbound in this type:</CODE><BR><CODE>  class b_point :</CODE><BR><CODE>    (#point as 'a) -&gt;</CODE><BR><CODE>    object val p : 'a method get : 'a method to_string : unit -&gt; string end</CODE><BR><CODE>The method get has type #point where .. is unbound</CODE><BR>

</PRE>
<BR>
<BR>
In fact, due to the constraint ``<B>constraint</B><CODE> </CODE><I>'a</I><CODE> </CODE><CODE>=</CODE><CODE> </CODE>#point'', the type of
<TT>get</TT> is the open type <I>#point</I>. The latter contains a free
variable type noted by a double point (<CODE>..</CODE>), which is not allowed.<BR>
<BR>

<H4> Inheritance and the Type of <TT>self</TT></H4>
<A NAME="sec-type-self"></A>
There exists an exception to the prohibition of a type variable in the type of
methods: a variable may stand for the type of the object itself
(<TT>self</TT>). Consider a method testing the equality
between two points.


<PRE><BR># <B>class</B><CODE> </CODE>point_eq<CODE> </CODE><TT>(</TT>x<CODE>,</CODE>y<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><CODE> </CODE><TT>(</TT>self<CODE> </CODE><CODE>:</CODE><CODE> </CODE><I>'a</I><TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE>point<CODE> </CODE><TT>(</TT>x<CODE>,</CODE>y<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>eq<CODE> </CODE><TT>(</TT>p<CODE>:</CODE><I>'a</I><TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT>self#get_x<CODE> </CODE><CODE>=</CODE><CODE> </CODE>p#get_x<TT>)</TT><CODE> </CODE><CODE>&amp;&amp;</CODE><CODE> </CODE><TT>(</TT>self#get_y<CODE> </CODE><CODE>=</CODE><CODE> </CODE>p#get_y<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR><CODE>class point_eq :</CODE><BR><CODE>  int * int -&gt;</CODE><BR><CODE>  object ('a)</CODE><BR><CODE>    val mutable x : int</CODE><BR><CODE>    val mutable y : int</CODE><BR><CODE>    method distance : unit -&gt; float</CODE><BR><CODE>    method eq : 'a -&gt; bool</CODE><BR><CODE>    method get_x : int</CODE><BR><CODE>    method get_y : int</CODE><BR><CODE>    method moveto : int * int -&gt; unit</CODE><BR><CODE>    method print : unit -&gt; unit</CODE><BR><CODE>    method rmoveto : int * int -&gt; unit</CODE><BR><CODE>    method to_string : unit -&gt; string</CODE><BR><CODE>  end</CODE><BR>

</PRE>

The type of method <TT>eq</TT> is <I>'a -&gt; bool</I>, but the type variable
stands for the type of the instance at construction time.<BR>
<BR>
You can inherit from the class <I>point_eq</I> and redefine the method <TT>eq</TT>,
whose type is still parameterized by the instance type.


<PRE><BR># <B>class</B><CODE> </CODE>colored_point_eq<CODE> </CODE><TT>(</TT>xc<CODE>,</CODE>yc<TT>)</TT><CODE> </CODE>c<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><CODE> </CODE><TT>(</TT>self<CODE> </CODE><CODE>:</CODE><CODE> </CODE><I>'a</I><TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE>point_eq<CODE> </CODE><TT>(</TT>xc<CODE>,</CODE>yc<TT>)</TT><CODE> </CODE><B>as</B><CODE> </CODE>super<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>c<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT>c<CODE>:</CODE>string<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>get_c<CODE> </CODE><CODE>=</CODE><CODE> </CODE>c<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>eq<CODE> </CODE><TT>(</TT>pc<CODE> </CODE><CODE>:</CODE><CODE> </CODE><I>'a</I><TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE> </CODE><TT>(</TT>self#get_x<CODE> </CODE><CODE>=</CODE><CODE> </CODE>pc#get_x<TT>)</TT><CODE> </CODE><CODE>&amp;&amp;</CODE><CODE> </CODE><TT>(</TT>self#get_y<CODE> </CODE><CODE>=</CODE><CODE> </CODE>pc#get_y<TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>&amp;&amp;</CODE><CODE> </CODE><TT>(</TT>self#get_c<CODE> </CODE><CODE>=</CODE><CODE> </CODE>pc#get_c<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR><CODE>class colored_point_eq :</CODE><BR><CODE>  int * int -&gt;</CODE><BR><CODE>  string -&gt;</CODE><BR><CODE>  object ('a)</CODE><BR><CODE>    val c : string</CODE><BR><CODE>    val mutable x : int</CODE><BR><CODE>    val mutable y : int</CODE><BR><CODE>    method distance : unit -&gt; float</CODE><BR><CODE>    method eq : 'a -&gt; bool</CODE><BR><CODE>    method get_c : string</CODE><BR><CODE>    method get_x : int</CODE><BR><CODE>    method get_y : int</CODE><BR><CODE>    method moveto : int * int -&gt; unit</CODE><BR><CODE>    method print : unit -&gt; unit</CODE><BR><CODE>    method rmoveto : int * int -&gt; unit</CODE><BR><CODE>    method to_string : unit -&gt; string</CODE><BR><CODE>  end</CODE><BR>

</PRE>
<BR>
<BR>
The method <TT>eq</TT> from class <I>colored_point_eq</I> still has type
<I>'a -&gt; bool</I>; but now the variable <I>'a</I> stands for the type of an
instance of class <I>colored_point_eq</I>. The definition of <TT>eq</TT>
in class <I>colored_point_eq</I> masks the inherited one. Methods
containing the type of the instance in their type are called binary methods. They will
cause some limitations in the subtyping relation described in page
<A HREF="book-ora144.html#sec-sous-typage">??</A>.<BR>
<BR>
<A NAME="toc209"></A>
<H3> Multiple Inheritance</H3><A NAME="subsec-heritage-multiple"></A>
<A NAME="@concepts329"></A>
With multiple inheritance, you can inherit data fields and methods from several
classes. When there are identical names for fields or methods, only the last
declaration is kept, according to the order of inheritance 
declarations. Nevertheless, it is possible to reference a method of one of the
parent classes by associating different names with the inherited classes.
This is not true for instance variables: if an inherited class masks an
instance variable of a previously inherited class, the latter is no longer
directly accessible. The various inherited classes do not need to have an
inheritance relation. Multiple inheritance is of interest because it increases
class reuse.<BR>
<BR>
Let us define the abstract class <I>geometric_object</I>, which declares two
virtual methods <TT>compute_area</TT> and <TT>compute_peri</TT> for
computing the area and perimeter.


<PRE><BR># <B>class</B><CODE> </CODE><B>virtual</B><CODE> </CODE>geometric_object<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE><B>virtual</B><CODE> </CODE>compute_area<CODE> </CODE><CODE>:</CODE><CODE> </CODE>unit<CODE> </CODE>-&gt;<CODE> </CODE>float<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE><B>virtual</B><CODE> </CODE>compute_peri<CODE> </CODE><CODE>:</CODE><CODE> </CODE>unit<CODE> </CODE>-&gt;<CODE> </CODE>float<BR><CODE> </CODE><B>end</B>;;<BR>

</PRE>
<BR>
<BR>
Then we redefine class <TT>rectangle</TT> as follows: 


<PRE><BR># <B>class</B><CODE> </CODE>rectangle_1<CODE> </CODE><TT>(</TT><TT>(</TT>p1<CODE>,</CODE>p2<TT>)</TT><CODE> </CODE><CODE>:</CODE><I>'a</I><TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>constraint</B><CODE> </CODE><I>'a</I><CODE> </CODE><CODE>=</CODE><CODE> </CODE>point<CODE> </CODE><CODE>*</CODE><CODE> </CODE>point<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE>printable<CODE> </CODE>()<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE>geometric_object<CODE> </CODE>()<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>llc<CODE> </CODE><CODE>=</CODE><CODE> </CODE>p1<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>urc<CODE> </CODE><CODE>=</CODE><CODE> </CODE>p2<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>to_string<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>"["</CODE><CODE>^</CODE>llc#to_string()<CODE>^</CODE><CODE>","</CODE><CODE>^</CODE>urc#to_string()<CODE>^</CODE><CODE>"]"</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>compute_area()<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>float<CODE> </CODE><TT>(</TT><CODE> </CODE>abs<TT>(</TT>urc#get_x<CODE> </CODE><CODE>-</CODE><CODE> </CODE>llc#get_x<TT>)</TT><CODE> </CODE><CODE>*</CODE><CODE> </CODE>abs<TT>(</TT>urc#get_y<CODE> </CODE><CODE>-</CODE><CODE> </CODE>llc#get_y<TT>)</TT><TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>compute_peri()<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>float<CODE> </CODE><TT>(</TT><CODE> </CODE><TT>(</TT>abs<TT>(</TT>urc#get_x<CODE> </CODE><CODE>-</CODE><CODE> </CODE>llc#get_x<TT>)</TT><CODE> </CODE><CODE>+</CODE><CODE> </CODE>abs<TT>(</TT>urc#get_y<CODE> </CODE><CODE>-</CODE><CODE> </CODE>llc#get_y<TT>)</TT><TT>)</TT><CODE> </CODE><CODE>*</CODE><CODE> </CODE><CODE>2</CODE><TT>)</TT><BR><CODE> </CODE><B>end</B>;;<BR><CODE>class rectangle_1 :</CODE><BR><CODE>  point * point -&gt;</CODE><BR><CODE>  object</CODE><BR><CODE>    val llc : point</CODE><BR><CODE>    val urc : point</CODE><BR><CODE>    method compute_area : unit -&gt; float</CODE><BR><CODE>    method compute_peri : unit -&gt; float</CODE><BR><CODE>    method print : unit -&gt; unit</CODE><BR><CODE>    method to_string : unit -&gt; string</CODE><BR><CODE>  end</CODE><BR>

</PRE>
<BR>
<BR>
This implementation of classes respects the inheritance graph of figure <A HREF="book-ora143.html#fig-hermult">15.5</A>.<BR>
<BR>
<BLOCKQUOTE><DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV>
<DIV ALIGN=center>
<IMG SRC="book-ora062.gif">
</DIV>
<BR>
<DIV ALIGN=center>Figure 15.5: Multiple inheritance.</DIV><BR>

<A NAME="fig-hermult"></A>
<DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV></BLOCKQUOTE>In order to avoid rewriting the methods of class <TT>rectangle</TT>, we may
directly inherit from <TT>rectangle</TT>, as shown in figure <A HREF="book-ora143.html#fig-hermult2">15.6</A>.<BR>
<BR>
<BLOCKQUOTE><DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV>
<DIV ALIGN=center>
<IMG SRC="book-ora063.gif"></DIV>
<BR>
<DIV ALIGN=center>Figure 15.6: Multiple inheritance (continued).</DIV><BR>

<A NAME="fig-hermult2"></A>
<DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV></BLOCKQUOTE>In such a case, only the abstract methods of the abstract class
<TT>geometric_object</TT> must be defined in <TT>rectangle_2</TT>.


<PRE><BR># <B>class</B><CODE> </CODE>rectangle_2<CODE> </CODE><TT>(</TT>p2<CODE> </CODE><CODE>:</CODE><I>'a</I><TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>constraint</B><CODE> </CODE><I>'a</I><CODE> </CODE><CODE>=</CODE><CODE> </CODE>point<CODE> </CODE><CODE>*</CODE><CODE> </CODE>point<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE>rectangle<CODE> </CODE>p2<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE>geometric_object<CODE> </CODE>()<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>compute_area()<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>float<CODE> </CODE><TT>(</TT><CODE> </CODE>abs<TT>(</TT>urc#get_x<CODE> </CODE><CODE>-</CODE><CODE> </CODE>llc#get_x<TT>)</TT><CODE> </CODE><CODE>*</CODE><CODE> </CODE>abs<TT>(</TT>urc#get_y<CODE> </CODE><CODE>-</CODE><CODE> </CODE>llc#get_y<TT>)</TT><TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>compute_peri()<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>float<CODE> </CODE><TT>(</TT><CODE> </CODE><TT>(</TT>abs<TT>(</TT>urc#get_x<CODE> </CODE><CODE>-</CODE><CODE> </CODE>llc#get_x<TT>)</TT><CODE> </CODE><CODE>+</CODE><CODE> </CODE>abs<TT>(</TT>urc#get_y<CODE> </CODE><CODE>-</CODE><CODE> </CODE>llc#get_y<TT>)</TT><TT>)</TT><CODE> </CODE><CODE>*</CODE><CODE> </CODE><CODE>2</CODE><TT>)</TT><BR><CODE> </CODE><B>end</B>;;<CODE> </CODE><CODE> </CODE><BR>

</PRE>
<BR>
<BR>
Continuing in the same vein, the hierarchies <TT>printable</TT> and
<TT>geometric_object</TT> could have been defined separately, until
it became useful to have a class with both behaviors. Figure
<A HREF="book-ora143.html#fig-hermult3">15.7</A> displays the relations defined in this way.<BR>
<BR>
<BLOCKQUOTE><DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV>
<DIV ALIGN=center>
<IMG SRC="book-ora064.gif">
</DIV>
<BR>
<DIV ALIGN=center>Figure 15.7: Multiple inheritance (end).</DIV><BR>

<A NAME="fig-hermult3"></A>
<DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV></BLOCKQUOTE>If we assume that classes <TT>printable_rect</TT> and
<TT>geometric_rect</TT> define instance variables for the corners of a
rectangle, we get class <TT>rectangle_3</TT> with four points (two per corner). 


<PRE><BR><B>class</B><CODE> </CODE>rectangle_3<CODE> </CODE><TT>(</TT>p1<CODE>,</CODE>p2<TT>)</TT><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><B>inherit</B><CODE> </CODE>printable_rect<CODE> </CODE><TT>(</TT>p1<CODE>,</CODE>p2<TT>)</TT><CODE> </CODE><B>as</B><CODE> </CODE>super_print<BR><CODE> </CODE><B>inherit</B><CODE> </CODE>geometric_rect<CODE> </CODE><TT>(</TT>p1<CODE>,</CODE>p2<TT>)</TT><CODE> </CODE><B>as</B><CODE> </CODE>super_geo<BR><B>end</B>;;<BR>

</PRE>

In the case where methods of the same type exist in both classes
<TT>..._rect</TT>, then only the last one is visible. However, by naming
parent classes (<TT>super_...</TT>), it is always possible to invoke a
method from either parent.<BR>
<BR>
Multiple inheritance allows factoring of the code by integrating methods
already written from various parent classes to build new
entities. The price paid is the size of constructed objects, which are bigger
than necessary due to duplicated fields, or inherited fields useless for a given
application. Furthermore, when there is duplication (as in our last
example), communication between these fields must be established manually
(update, etc.). In the last example for class <TT>rectangle_3</TT>, we obtain
instance variables of classes <TT>printable_rect</TT> and
<TT>geometric_rect</TT>. If one of these classes has a method which modifies
these variables (such as a scaling factor), then it is necessary to propagate
these modifications to variables inherited from the other class. Such a heavy
communication between inherited instance variables often signals a poor
modeling of the given problem.<BR>
<BR>
<A NAME="toc210"></A>
<H3> Parameterized Classes</H3>
<A NAME="subsec-parameterized-class"></A>
<A NAME="@concepts330"></A>
Parameterized classes let Objective CAML's parameterized
polymorphism be used in classes. As with the type declarations of Objective CAML,
class declarations can be parameterized with type variables. This provides new opportunities for
genericity and code reuse. Parameterized classes are integrated with ML-like typing when type
inference produces parameterized types.<BR>
<BR>
The syntax differs slightly from the declaration of parameterized types; type
parameters are between brackets.


<H3> Syntax </H3> <HR>


<B>class</B> <B>[</B><I>'a</I>, <I>'b</I>, ...<B>]</B>
<I>name</I> <B>=</B> <B>object</B> ...<B>end</B>



<HR>


The Objective CAML type is noted as usual:
<I>('a,'b,...) name</I>. <BR>
<BR>
For instance, if a class <TT>pair</TT> is required, a naive solution would be to set:


<PRE><BR># <B>class</B><CODE> </CODE>pair<CODE> </CODE>x0<CODE> </CODE>y0<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>x<CODE> </CODE><CODE>=</CODE><CODE> </CODE>x0<CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>y<CODE> </CODE><CODE>=</CODE><CODE> </CODE>y0<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>fst<CODE> </CODE><CODE>=</CODE><CODE> </CODE>x<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>snd<CODE> </CODE><CODE>=</CODE><CODE> </CODE>y<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><BR><CODE>Characters 6-106:</CODE><BR><CODE>Some type variables are unbound in this type:</CODE><BR><CODE>  class pair :</CODE><BR><CODE>    'a -&gt;</CODE><BR><CODE>    'b -&gt; object val x : 'a val y : 'b method fst : 'a method snd : 'b end</CODE><BR><CODE>The method fst has type 'a where 'a is unbound</CODE><BR>

</PRE>
<BR>
<BR>
One again gets the typing error mentioned when class <I>a_point</I> was
defined (page <A HREF="book-ora143.html#subsec-classes-types-objets">??</A>). The error message says
that type variable <I>'a</I>, assigned to parameter <TT>x0</TT> (and
therefore to <TT>x</TT> and <TT>fst</TT>), is not bound. <BR>
<BR>
As in the case of parameterized types, it is necessary to parameterize class
<I>pair</I> with two type variables, and force the type of construction parameters
<TT>x0</TT> and <TT>y0</TT> to obtain a correct typing:


<PRE><BR># <B>class</B><CODE> </CODE><CODE>[</CODE><I>'a</I><CODE>,</CODE><I>'b</I><CODE>]</CODE><CODE> </CODE>pair<CODE> </CODE><TT>(</TT>x0<CODE>:</CODE><I>'a</I><TT>)</TT><CODE> </CODE><TT>(</TT>y0<CODE>:</CODE><I>'b</I><TT>)</TT><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>x<CODE> </CODE><CODE>=</CODE><CODE> </CODE>x0<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>y<CODE> </CODE><CODE>=</CODE><CODE> </CODE>y0<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>fst<CODE> </CODE><CODE>=</CODE><CODE> </CODE>x<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>snd<CODE> </CODE><CODE>=</CODE><CODE> </CODE>y<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR><CODE>class ['a, 'b] pair :</CODE><BR><CODE>  'a -&gt;</CODE><BR><CODE>  'b -&gt; object val x : 'a val y : 'b method fst : 'a method snd : 'b end</CODE><BR>

</PRE>

Type inference displays a class interface parameterized by variables of type
<TT>'a</TT> and <TT>'b</TT>.<BR>
<BR>
When a value of a parameterized class is constructed, type parameters are
instantiated with the types of the construction parameters:


<PRE><BR># <B>let</B><CODE> </CODE>p<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>new</B><CODE> </CODE>pair<CODE> </CODE><CODE>2</CODE><CODE> </CODE><CODE>'X'</CODE>;;<BR><CODE>val p : (int, char) pair = &lt;obj&gt;</CODE><BR># p#fst;;<BR><CODE>- : int = 2</CODE><BR># <B>let</B><CODE> </CODE>q<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>new</B><CODE> </CODE>pair<CODE> </CODE><CODE>3</CODE><CODE>.</CODE><CODE>1</CODE><CODE>2</CODE><CODE> </CODE><B>true</B>;;<BR><CODE>val q : (float, bool) pair = &lt;obj&gt;</CODE><BR># q#snd;;<BR><CODE>- : bool = true</CODE><BR>

</PRE>
<BR>
<BR>


<H3> Note </H3> <HR>

In class declarations, type parameters are shown between brackets, but in
types, they are shown between parentheses.


<HR>

<BR>
<BR>

<H4> Inheritance of Parameterized Classes</H4>
When inheriting from a parameterized class, one has to indicate the parameters
of the class.
Let us define a class <I>acc_pair</I> that inherits from <I>('a,'b) pair</I>;
we add two methods for accessing the fields,
<TT>get1</TT> and <TT>get2</TT>,


<PRE><BR># <B>class</B><CODE> </CODE><CODE>[</CODE><I>'a</I><CODE>,</CODE><I>'b</I><CODE>]</CODE><CODE> </CODE>acc_pair<CODE> </CODE><TT>(</TT>x0<CODE> </CODE><CODE>:</CODE><CODE> </CODE><I>'a</I><TT>)</TT><CODE> </CODE><TT>(</TT>y0<CODE> </CODE><CODE>:</CODE><CODE> </CODE><I>'b</I><TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE><CODE>[</CODE><I>'a</I><CODE>,</CODE><I>'b</I><CODE>]</CODE><CODE> </CODE>pair<CODE> </CODE>x0<CODE> </CODE>y0<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>get1<CODE> </CODE>z<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>if</B><CODE> </CODE>x<CODE> </CODE><CODE>=</CODE><CODE> </CODE>z<CODE> </CODE><B>then</B><CODE> </CODE>y<CODE> </CODE><B>else</B><CODE> </CODE>raise<CODE> </CODE>Not_found<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>get2<CODE> </CODE>z<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>if</B><CODE> </CODE>y<CODE> </CODE><CODE>=</CODE><CODE> </CODE>z<CODE> </CODE><B>then</B><CODE> </CODE>x<CODE> </CODE><B>else</B><CODE> </CODE>raise<CODE> </CODE>Not_found<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B>;;<BR><CODE>class ['a, 'b] acc_pair :</CODE><BR><CODE>  'a -&gt;</CODE><BR><CODE>  'b -&gt;</CODE><BR><CODE>  object</CODE><BR><CODE>    val x : 'a</CODE><BR><CODE>    val y : 'b</CODE><BR><CODE>    method fst : 'a</CODE><BR><CODE>    method get1 : 'a -&gt; 'b</CODE><BR><CODE>    method get2 : 'b -&gt; 'a</CODE><BR><CODE>    method snd : 'b</CODE><BR><CODE>  end</CODE><BR># <B>let</B><CODE> </CODE>p<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>new</B><CODE> </CODE>acc_pair<CODE> </CODE><CODE>3</CODE><CODE> </CODE><B>true</B>;;<BR><CODE>val p : (int, bool) acc_pair = &lt;obj&gt;</CODE><BR># p#get1<CODE> </CODE><CODE>3</CODE>;;<BR><CODE>- : bool = true</CODE><BR>

</PRE>
<BR>
<BR>
We can make the type parameters of the inherited parameterized class more precise,
e.g. for a pair of points.


<PRE><BR># <B>class</B><CODE> </CODE>point_pair<CODE> </CODE><TT>(</TT>p1<CODE>,</CODE>p2<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE><CODE>[</CODE>point<CODE>,</CODE>point<CODE>]</CODE><CODE> </CODE>pair<CODE> </CODE>p1<CODE> </CODE>p2<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B>;;<BR><CODE>class point_pair :</CODE><BR><CODE>  point * point -&gt;</CODE><BR><CODE>  object</CODE><BR><CODE>    val x : point</CODE><BR><CODE>    val y : point</CODE><BR><CODE>    method fst : point</CODE><BR><CODE>    method snd : point</CODE><BR><CODE>  end</CODE><BR>

</PRE>
<BR>
<BR>
Class <I>point_pair</I> no longer needs type parameters, since parameters
<I>'a</I> and <I>'b</I> are completely determined.<BR>
<BR>
To build pairs of displayable objects (i.e. having a method <TT>print</TT>), we
reuse the abstract class <TT>printable</TT> (see page <A HREF="book-ora143.html#ex-printable">??</A>),
then we define the class <TT>printable_pair</TT> which inherits from <TT>pair</TT>.


<PRE><BR># <B>class</B><CODE> </CODE>printable_pair<CODE> </CODE>x0<CODE> </CODE>y0<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE><CODE>[</CODE>printable<CODE>,</CODE><CODE> </CODE>printable<CODE>]</CODE><CODE> </CODE>acc_pair<CODE> </CODE>x0<CODE> </CODE>y0<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>print<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>x#print();<CODE> </CODE>y#print<CODE> </CODE>()<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B>;;<BR>

</PRE>
<BR>
<BR>
This implementation allows us to construct pairs of instances of
<TT>printable</TT>, but it cannot be used for objects of another class with a
method <TT>print</TT>.<BR>
<BR>
We could try to open type <TT>printable</TT> used as a type parameter for
<TT>acc_pair</TT>:


<PRE><BR># <B>class</B><CODE> </CODE>printable_pair<CODE> </CODE><TT>(</TT>x0<CODE> </CODE><TT>)</TT><CODE> </CODE><TT>(</TT>y0<CODE> </CODE><TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE><CODE>[</CODE><CODE> </CODE>#printable<CODE>,</CODE><CODE> </CODE>#printable<CODE> </CODE><CODE>]</CODE><CODE> </CODE>acc_pair<CODE> </CODE>x0<CODE> </CODE>y0<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>print<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>x#print();<CODE> </CODE>y#print<CODE> </CODE>()<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B>;;<BR><CODE>Characters 6-149:</CODE><BR><CODE>Some type variables are unbound in this type:</CODE><BR><CODE>  class printable_pair :</CODE><BR><CODE>    (#printable as 'a) -&gt;</CODE><BR><CODE>    (#printable as 'b) -&gt;</CODE><BR><CODE>    object</CODE><BR><CODE>      val x : 'a</CODE><BR><CODE>      val y : 'b</CODE><BR><CODE>      method fst : 'a</CODE><BR><CODE>      method get1 : 'a -&gt; 'b</CODE><BR><CODE>      method get2 : 'b -&gt; 'a</CODE><BR><CODE>      method print : unit -&gt; unit</CODE><BR><CODE>      method snd : 'b</CODE><BR><CODE>    end</CODE><BR><CODE>The method fst has type #printable where .. is unbound</CODE><BR>

</PRE>

This first attempt fails because methods <TT>fst</TT> and <TT>snd</TT> contain
an open type.<BR>
<BR>
So we shall keep the type parameters of the class, while constraining them to
the open type <I>#printable</I>.


<PRE><BR># <B>class</B><CODE> </CODE><CODE>[</CODE><I>'a</I><CODE>,</CODE><I>'b</I><CODE>]</CODE><CODE> </CODE>printable_pair<CODE> </CODE><TT>(</TT>x0<CODE> </CODE><TT>)</TT><CODE> </CODE><TT>(</TT>y0<CODE> </CODE><TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>constraint</B><CODE> </CODE><I>'a</I><CODE> </CODE><CODE>=</CODE><CODE> </CODE>#printable<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>constraint</B><CODE> </CODE><I>'b</I><CODE> </CODE><CODE>=</CODE><CODE> </CODE>#printable<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE><CODE>[</CODE><I>'a</I><CODE>,</CODE><I>'b</I><CODE>]</CODE><CODE> </CODE>acc_pair<CODE> </CODE>x0<CODE> </CODE>y0<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>print<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>x#print();<CODE> </CODE>y#print<CODE> </CODE>()<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B>;;<BR><CODE>class ['a, 'b] printable_pair :</CODE><BR><CODE>  'a -&gt;</CODE><BR><CODE>  'b -&gt;</CODE><BR><CODE>  object</CODE><BR><CODE>    constraint 'a = #printable</CODE><BR><CODE>    constraint 'b = #printable</CODE><BR><CODE>    val x : 'a</CODE><BR><CODE>    val y : 'b</CODE><BR><CODE>    method fst : 'a</CODE><BR><CODE>    method get1 : 'a -&gt; 'b</CODE><BR><CODE>    method get2 : 'b -&gt; 'a</CODE><BR><CODE>    method print : unit -&gt; unit</CODE><BR><CODE>    method snd : 'b</CODE><BR><CODE>  end</CODE><BR>

</PRE>
<BR>
<BR>
Then we construct a displayable pair containing a point and a colored point.


<PRE><BR># <B>let</B><CODE> </CODE>pp<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>new</B><CODE> </CODE>printable_pair<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT><B>new</B><CODE> </CODE>point<CODE> </CODE><TT>(</TT><CODE>1</CODE><CODE>,</CODE><CODE>2</CODE><TT>)</TT><TT>)</TT><CODE> </CODE><TT>(</TT><B>new</B><CODE> </CODE>colored_point<CODE> </CODE><TT>(</TT><CODE>3</CODE><CODE>,</CODE><CODE>4</CODE><TT>)</TT><CODE> </CODE><CODE>"green"</CODE><TT>)</TT>;;<BR><CODE>val pp : (point, colored_point) printable_pair = &lt;obj&gt;</CODE><BR># pp#print();;<BR><CODE>( 1, 2)( 3, 4) with color green- : unit = ()</CODE><BR>

</PRE>
<BR>
<BR>

<H4> Parameterized Classes and Typing</H4>
From the point of view of types, a parameterized class is a parameterized
type. A value of such a type can contain weak type variables.


<PRE><BR># <B>let</B><CODE> </CODE>r<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>new</B><CODE> </CODE>pair<CODE> </CODE>[]<CODE> </CODE>[];;<BR><CODE>val r : ('_a list, '_b list) pair = &lt;obj&gt;</CODE><BR># r#fst;;<BR><CODE>- : '_a list = []</CODE><BR># r#fst<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>[</CODE><CODE>1</CODE>;<CODE>2</CODE><CODE>]</CODE>;;<BR><CODE>- : bool = false</CODE><BR># r;;<BR><CODE>- : (int list, '_a list) pair = &lt;obj&gt;</CODE><BR>

</PRE>
<BR>
<BR>
A parameterized class can also be viewed as a closed object type; therefore
nothing prevents us from also using it as an open type with the sharp
notation.


<PRE><BR># <B>let</B><CODE> </CODE>compare_nothing<CODE> </CODE><TT>(</TT><CODE> </CODE>x<CODE> </CODE><CODE>:</CODE><CODE> </CODE><TT>(</TT><I>'a</I><CODE>,</CODE><CODE> </CODE><I>'a</I><TT>)</TT><CODE> </CODE>#pair<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>if</B><CODE> </CODE>x#fst<CODE> </CODE><CODE>=</CODE><CODE> </CODE>x#fst<CODE> </CODE><B>then</B><CODE> </CODE>x#mess<CODE> </CODE><B>else</B><CODE> </CODE>x#mess2;;<BR><CODE>val compare_nothing :</CODE><BR><CODE>  &lt; fst : 'a; mess : 'b; mess2 : 'b; snd : 'a; .. &gt; -&gt; 'b = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
This lets us construct parameterized types that contain weak type
variables that are also open object types.


<PRE><BR># <B>let</B><CODE> </CODE>prettytype<CODE> </CODE>x<CODE> </CODE><TT>(</TT><CODE> </CODE>y<CODE> </CODE><CODE>:</CODE><CODE> </CODE><TT>(</TT><I>'a</I><CODE>,</CODE><CODE> </CODE><I>'a</I><TT>)</TT><CODE> </CODE>#pair<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>if</B><CODE> </CODE>x<CODE> </CODE><CODE>=</CODE><CODE> </CODE>y#fst<CODE> </CODE><B>then</B><CODE> </CODE>y<CODE> </CODE><B>else</B><CODE> </CODE>y;;<BR><CODE>val prettytype : 'a -&gt; (('a, 'a) #pair as 'b) -&gt; 'b = &lt;fun&gt;</CODE><BR>

</PRE>
 <BR>
<BR>
If this function is applied to one parameter, we get a closure, whose type
variables are weak. An open type, such as <I>#pair</I>, still contains
uninstantiated parts, represented by the double point (..). In this respect,
an open type is a partially known type parameter. Upon weakening
such a type after a partial application, the displayer specifies that the
type variable representing this open type has been weakened. Then the notation
is <I>_#pair</I>.<BR>
<BR>


<PRE><BR># <B>let</B><CODE> </CODE>g<CODE> </CODE><CODE>=</CODE><CODE> </CODE>prettytype<CODE> </CODE><CODE>3</CODE>;;<BR><CODE>val g : ((int, int) _#pair as 'a) -&gt; 'a = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
Now, if function <TT>g</TT> is applied to a pair, its weak type is modified.


<PRE><BR># g<CODE> </CODE><TT>(</TT><B>new</B><CODE> </CODE>acc_pair<CODE> </CODE><CODE>2</CODE><CODE> </CODE><CODE>3</CODE><TT>)</TT>;;<BR><CODE>- : (int, int) acc_pair = &lt;obj&gt;</CODE><BR># g;;<BR><CODE>- : (int, int) acc_pair -&gt; (int, int) acc_pair = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
Then we can no longer use <TT>g</TT> on simple pairs.


<PRE><BR># g<CODE> </CODE><TT>(</TT><B>new</B><CODE> </CODE>pair<CODE> </CODE><CODE>1</CODE><CODE> </CODE><CODE>1</CODE><TT>)</TT>;;<BR><CODE>Characters 4-16:</CODE><BR><CODE>This expression has type (int, int) pair = &lt; fst : int; snd : int &gt;</CODE><BR><CODE>but is here used with type</CODE><BR><CODE>  (int, int) acc_pair =</CODE><BR><CODE>    &lt; fst : int; get1 : int -&gt; int; get2 : int -&gt; int; snd : int &gt;</CODE><BR><CODE>Only the second object type has a method get1</CODE><BR>

</PRE>
<BR>
<BR>
Finally, since parameters of the parameterized class can also get weakened, we
obtain the following example.


<PRE><BR># <B>let</B><CODE> </CODE>h<CODE> </CODE><CODE>=</CODE><CODE> </CODE>prettytype<CODE> </CODE>[];;<BR><CODE>val h : (('_b list, '_b list) _#pair as 'a) -&gt; 'a = &lt;fun&gt;</CODE><BR># <B>let</B><CODE> </CODE>h2<CODE> </CODE><CODE>=</CODE><CODE> </CODE>h<CODE> </CODE><TT>(</TT><B>new</B><CODE> </CODE>pair<CODE> </CODE>[]<CODE> </CODE><CODE>[</CODE><CODE>1</CODE>;<CODE>2</CODE><CODE>]</CODE><TT>)</TT>;;<BR><CODE>val h2 : (int list, int list) pair = &lt;obj&gt;</CODE><BR># h;;<BR><CODE>- : (int list, int list) pair -&gt; (int list, int list) pair = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
The type of the parameter of <TT>h</TT> is no longer open. The following
application cannot be typed because the argument is not of type <I>pair</I>.


<PRE><BR># h<CODE> </CODE><TT>(</TT><B>new</B><CODE> </CODE>acc_pair<CODE> </CODE>[]<CODE> </CODE><CODE>[</CODE><CODE>4</CODE>;<CODE>5</CODE><CODE>]</CODE><TT>)</TT>;;<BR><CODE>Characters 4-25:</CODE><BR><CODE>This expression has type</CODE><BR><CODE>  ('a list, int list) acc_pair =</CODE><BR><CODE>    &lt; fst : 'a list; get1 : 'a list -&gt; int list; get2 : int list -&gt; 'a list;</CODE><BR><CODE>      snd : int list &gt;</CODE><BR><CODE>but is here used with type</CODE><BR><CODE>  (int list, int list) pair = &lt; fst : int list; snd : int list &gt;</CODE><BR><CODE>Only the first object type has a method get1</CODE><BR>

</PRE>
<BR>
<BR>


<H3> Note </H3> <HR>

Parameterized classes of Objective CAML are absolutely necessary as soon as one has
methods whose type includes a type variable different from the type of
<TT>self</TT>.


<HR>

<BR>
<BR>
<HR>
<A HREF="book-ora142.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora144.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
</BODY>
</HTML>
